﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Reflection;
using System.Collections.Concurrent;

namespace CommonsLib.ORM
{
    public class ORMFunc
    {
        private const string NO_IDENTITY = "No Identity";

        private static ConcurrentDictionary<string, string> _dictKeyName = new ConcurrentDictionary<string, string>();
        private static ConcurrentDictionary<string, string> _dictForeignKeyName = new ConcurrentDictionary<string, string>();
        private static ConcurrentDictionary<string, string> _dictIdentityName = new ConcurrentDictionary<string, string>();
        private static ConcurrentDictionary<string, string> _dictDBname = new ConcurrentDictionary<string, string>();
        private static ConcurrentDictionary<string, string> _dictTablename = new ConcurrentDictionary<string, string>();
        private static ConcurrentDictionary<string, string> _dictFields = new ConcurrentDictionary<string, string>();
        private static ConcurrentDictionary<string, string> _dictProps = new ConcurrentDictionary<string, string>();


        public static string GetKey(Type objType)
        {
            string strKey =_dictKeyName.ContainsKey(objType.FullName)?  _dictKeyName[objType.FullName]:string.Empty;

            if (strKey.Length==0)
            {
                DataTableAttribute ObjAttr = objType.GetCustomAttributes(typeof(DataTableAttribute), false)[0] as DataTableAttribute;
                if (ObjAttr != null)
                {
                    strKey = ObjAttr.Key;
                }
                else
                {
                    throw new Exception(objType.ToString() + ".Attributes不属于DataTableAttribute。");
                }

                if (strKey.Length==0)
                {
                    throw new Exception(objType.ToString() + ".DataTableAttribute没有设置Key属性。");
                }

                _dictKeyName[objType.FullName] = strKey;
            }
            return strKey;
        }

        public static string GetForeignKey(Type objType)
        {
            string strForeignKey = _dictForeignKeyName.ContainsKey(objType.FullName) ? _dictForeignKeyName[objType.FullName] : string.Empty;

            if (strForeignKey.Length == 0)
            {
                DataTableAttribute ObjAttr = objType.GetCustomAttributes(typeof(DataTableAttribute), false)[0] as DataTableAttribute;
                if (ObjAttr != null)
                {
                    strForeignKey = ObjAttr.ForeignKey;
                }
                else
                {
                    throw new Exception(objType.ToString() + ".Attributes不属于DataTableAttribute。");
                }

                if (strForeignKey.Length == 0)
                {
                    throw new Exception(objType.ToString() + ".DataTableAttribute没有设置ForeignKey属性。");
                }

                _dictForeignKeyName[objType.FullName] = strForeignKey;
            }
            return strForeignKey;
        }
        
        public static string GetTableName(Type objType)
        {
            string strTablename = _dictTablename.ContainsKey(objType.FullName) ? _dictTablename[objType.FullName] : string.Empty;  

            if (strTablename.Length==0)
            {
                DataTableAttribute ObjAttr = objType.GetCustomAttributes(typeof(DataTableAttribute), false)[0] as DataTableAttribute;
                if (ObjAttr != null)
                {
                    strTablename = ObjAttr.TableName;
                }
                else
                {
                    throw new Exception(objType.ToString() + ".Attributes不属于DataTableAttribute。");
                }

                if (strTablename.Length==0)
                {
                    throw new Exception(objType.ToString() + "没有设置TableName属性。");
                }

                _dictTablename[objType.FullName] = strTablename;
            }

            return strTablename;
        }
        public static string GetDBName(Type objType)
        {
            string strDBname = _dictDBname.ContainsKey(objType.FullName) ? _dictDBname[objType.FullName] : string.Empty;  

            if (strDBname.Length == 0)
            {
                DataTableAttribute ObjAttr = objType.GetCustomAttributes(typeof(DataTableAttribute), false)[0] as DataTableAttribute;
                if (ObjAttr != null)
                {
                    strDBname = ObjAttr.DBName;
                }
                else
                {
                    throw new Exception(objType.ToString() + ".Attributes不属于DataTableAttribute。");
                }

                if (strDBname.Length == 0)
                {
                    throw new Exception(objType.ToString() + "没有设置DBname属性。");
                }

                _dictDBname[objType.FullName] = strDBname;
            }

            return strDBname;
        }

        public static string GetIdentityName(Type objType)
        {
            string strIdentityName = _dictIdentityName.ContainsKey(objType.FullName) ? _dictIdentityName[objType.FullName] : string.Empty; 


            if (strIdentityName.Length == 0  )
            {
                strIdentityName = NO_IDENTITY;
                //反射设置ModelObject的属性
                PropertyInfo[] props = objType.GetProperties();
                DataFieldAttribute FieldAttr = null;

                object[] CustomAttributes;

                foreach (PropertyInfo prop in props)
                {
                    CustomAttributes = prop.GetCustomAttributes(typeof(DataFieldAttribute), false);
                    if (CustomAttributes.Length > 0)
                    {
                        FieldAttr = CustomAttributes[0] as DataFieldAttribute;
                        if (FieldAttr != null && FieldAttr.IsIdentity)
                        {
                            strIdentityName=FieldAttr.FieldName;
                        }
                    }

                }


                _dictIdentityName[objType.FullName] = strIdentityName;
            }


            return strIdentityName;
             
        }

        public static  string GetFields(Type objType,bool blnFields)
        {
            string strFields = _dictFields.ContainsKey(objType.FullName) ? _dictFields[objType.FullName] : string.Empty;
            string strProps = _dictProps.ContainsKey(objType.FullName) ? _dictProps[objType.FullName] : string.Empty; 

            if (strFields.Length == 0 || strProps.Length == 0)
            {
                List<string> lstFields = new List<string>();
                List<string> lstProps = new List<string>();
                //反射设置ModelObject的属性
                PropertyInfo[] props = objType.GetProperties();
                DataFieldAttribute FieldAttr = null;

                object[] CustomAttributes;
                
                foreach (PropertyInfo prop in props)
                {
                    CustomAttributes = prop.GetCustomAttributes(typeof(DataFieldAttribute), false);
                    if (CustomAttributes.Length > 0)
                    {
                        FieldAttr = CustomAttributes[0] as DataFieldAttribute;
                        if (FieldAttr != null)
                        {
                            lstFields.Add(FieldAttr.FieldName);
                            lstProps.Add(prop.Name);   
                        }
                    }

                }

                strFields =string.Join(",", lstFields.ToArray<string>());
                strProps =string.Join(",", lstProps.ToArray<string>());
                if (strFields.Length == 0)
                {
                    throw new Exception(objType.ToString() + "没有设置DataFieldAttribute属性。");
                }

                _dictFields[objType.FullName] = strFields;
                _dictProps[objType.FullName] = strProps;
            }

            if (blnFields)
            {
                return strFields;
            }
            else
            {
                return strProps;
            }
        }
     
        public static void SetKeyValue(object modelObject, object keyValue)
        {
            Type type = modelObject.GetType();
            string strFullName = type.FullName;
            string strKeyName = GetKey(type);


            string[] arrFields = GetFields(type, true).Split(',');
            string[] arrProps = GetFields(type, false).Split(',');

            

            for (int i = 0; i < arrFields.Length; i++)
            {

                PropertyInfo prop = modelObject.GetType().GetProperty(arrProps[i]);
                if (strKeyName.Equals(arrFields[i], StringComparison.InvariantCultureIgnoreCase))
                {
                    prop.SetValue(modelObject,Convert.ChangeType( keyValue,prop.PropertyType), null);
                }
            }

            
        }

        public static void SetIdentityValue(object modelObject, object identityValue)
        {
            Type objType = modelObject.GetType();
            string strFullName = objType.FullName;
            string strIdentityName = _dictIdentityName.ContainsKey(objType.FullName) ? _dictIdentityName[objType.FullName] : string.Empty;  

            if (strIdentityName.Equals(NO_IDENTITY))
            {
                return;
            }
            else if (strIdentityName.Length == 0)
            {
                strIdentityName = GetIdentityName(objType);
                if (strIdentityName.Equals(NO_IDENTITY))
                {
                    return;
                }
            }

 


            string[] arrFields = GetFields(objType, true).Split(',');
            string[] arrProps = GetFields(objType, false).Split(',');



            for (int i = 0; i < arrFields.Length; i++)
            {

                PropertyInfo prop = modelObject.GetType().GetProperty(arrProps[i]);
                if (strIdentityName.Equals(arrFields[i], StringComparison.InvariantCultureIgnoreCase))
                {
                    prop.SetValue(modelObject, Convert.ChangeType(identityValue, prop.PropertyType), null);
                   
                }
            }
        }



        public static void Read(object ModelObject, System.Data.Common.DbDataReader rdr)
        {
            Type objType=ModelObject.GetType();
            string[] arrFields = GetFields(objType,true).Split(',');
            string[] arrProps = GetFields(objType, false).Split(',');
            for (int i = 0; i < arrFields.Length; i++)
            {
                //反射设置ModelObject的属性
                PropertyInfo prop = ModelObject.GetType().GetProperty(arrProps[i]);
                object obj=((prop.PropertyType ==typeof(string))?rdr.GetString(i).TrimEnd(): Convert.ChangeType(rdr[i], prop.PropertyType));
                
                 prop.SetValue(ModelObject,obj, null);
            }
        }

        public static object[] GetValues(object ModelObject)
        {
            return GetValues( ModelObject,true);
        }
        public static object[] GetValues(object ModelObject, bool blnIgnoreIdentity)
        {
            Type objType = ModelObject.GetType();
            string[] arrFields = GetFields(objType, true).Split(',');
            string[] arrProps = GetFields(objType, false).Split(',');
            object[] datas = new object[arrFields.Length];
            string strIdentityName = string.Empty;
            if (blnIgnoreIdentity)
            {
                strIdentityName = GetIdentityName(objType);
            }
            for (int i = 0; i < arrFields.Length; i++)
            {
                
                PropertyInfo prop = ModelObject.GetType().GetProperty(arrProps[i]);
                if (!(blnIgnoreIdentity && strIdentityName.Equals(arrFields[i], StringComparison.InvariantCultureIgnoreCase)))
                {
                    datas[i] = prop.GetValue(ModelObject, null);
                }
            }

            return datas;
        }

        public static object GetKeyValue(object ModelObject)
        {
            Type objType = ModelObject.GetType();
            string[] arrFields = GetFields(objType, true).Split(',');
            string[] arrProps = GetFields(objType, false).Split(',');
             
            string strKeyName = GetKey(objType);
             
            for (int i = 0; i < arrFields.Length; i++)
            {

                PropertyInfo prop = ModelObject.GetType().GetProperty(arrProps[i]);
                if ( strKeyName.Equals(arrFields[i], StringComparison.InvariantCultureIgnoreCase))
                {
                    return prop.GetValue(ModelObject, null);
                }
            }

            return null;
        }
    }
}
